﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading;

namespace Gargoyle.Roton
{
    /// <summary>
    /// A timer that creates a thread and does polling.
    /// </summary>
    public class EventTimer : IDisposable
    {
        private bool Disposed = false;
        private bool Enabled;
        private long Interval;
        private int MaxSimultaneousEvents;
        private long PreviousTick;
        private Stopwatch Stopwatch;
        private Thread TimerThread;

        /// <summary>
        /// Create a new EventTimer.
        /// </summary>
        /// <param name="newCallback">The function to call on a tick.</param>
        /// <param name="newFrequency">The number of ticks per second.</param>
        /// <param name="newMaxSimultaneousEvents">The maximum number of times a timer will run the callback per tick when it falls behind.</param>
        public EventTimer(EventHandler newCallback, double newFrequency, int newMaxSimultaneousEvents)
        {
            MaxSimultaneousEvents = newMaxSimultaneousEvents;
            Enabled = false;
            Stopwatch = new Stopwatch();
            SetInterval(newFrequency);
            TimerThread = new Thread(Tick);
            TimerThread.Start(newCallback);
        }

        ~EventTimer()
        {
            Disposed = true;
        }
        
        /// <summary>
        /// Release resources used by this EventTimerSimple.
        /// </summary>
        public void Dispose()
        {
            Disposed = true;
        }

        private void Reset()
        {
            PreviousTick = 0;
            Stopwatch.Reset();
            if (Enabled)
                Stopwatch.Start();
        }

        /// <summary>
        /// Set the number of ticks per second.
        /// </summary>
        /// <param name="newFrequency">Number of ticks per second.</param>
        public void SetInterval(double newFrequency)
        {
            Interval = (long)((double)Stopwatch.Frequency / newFrequency);
            Reset();
        }

        /// <summary>
        /// Start the timer.
        /// </summary>
        public void Start()
        {
            Enabled = true;
            Reset();
        }

        /// <summary>
        /// Stop the timer.
        /// </summary>
        public void Stop()
        {
            Enabled = false;
            Reset();
        }

        private void Tick(object eh)
        {
            EventHandler Callback = (EventHandler)eh;

            while (!Disposed)
            {
                long currentTick = Stopwatch.ElapsedTicks;
                int events = 0;
                if (Enabled)
                {
                    while (PreviousTick <= currentTick)
                    {
                        Callback(this, EventArgs.Empty);
                        PreviousTick += Interval;
                        events++;
                        if (events > MaxSimultaneousEvents)
                        {
                            PreviousTick = currentTick;
                            break;
                        }
                    }
                }
                Thread.Sleep(1);
            }
        }
    }
}
